# -*- encoding:utf-8 -*-
# @Time: 2022/11/9 23:54
# @Author :xibin
# @Email: xibin@maqu. com
# @File: verifyUtil.py
# @Software: PyCharm
import os
import random
import string
from PIL import Image,ImageFont,ImageDraw,ImageFilter  #ImageFilter是滤镜
from django_redis import get_redis_connection

from config.dbs.redis_rev import LOGIN_KEY_TEMPLATE

"""
      --------验证码生成---------
"""

class ImageVerify: #图像验证码的类
    def __init__(self,x=140,y=40,length=4,size=28):
        """
        初始化
        :param x: 图片宽度
        :param y: 图片高度
        :param length: 字符个数
        :param size: 字体大小
        """
        self.x = x
        self.y = y
        self.length = length
        self.size = size

    def random_str(self): #生成随机字符
        """
        随机生成指定字符的字符串
        数据源：26个字母和10个数字
        :return: 返回生成的字符串
        """
        source = string.ascii_letters + string.digits #前面是所有大小写字母，后面是10个数字，可以点进去看一下string的用法
        return ''.join(random.sample(source,self.length)) #随机选择方法，后面是个数,因为随处出来的数是列表，所以用join拼接一下，编程字符串

    def random_color(self,start=0,end=255):
        """
        随机生成RGB颜色
        :param start: 颜色范围的最小值
        :param end: 颜色范围的最大值
        :return: tuple(r,g,b) 每个的范围是0-255
        """
        res = [random.randint(start,end) for i in range(3)] #列表

        return tuple(res) #tuple转元组

    def random_lines(self,draw):
        """
        绘制干扰线
        :param draw: draw对象  画笔
        :return: 不需要返回值，直接画上去
        """
        for i in range(10):
            lines = [(random.randint(0,self.x),random.randint(0,self.y)) for i in range(2)] #先生成一个点，x坐标和 y坐标,循环两次得到一条线的随机的两点
            draw.line(lines,fill=self.random_color(50,200))#用笔画线，两点是刚才得到的lines，然后fill是用什么颜色，这里使用rgb50-200的颜色

    def random_points(self,draw,rate):
        """
        绘制干扰点，一个个小点点
        :param draw: 画笔
        :param rate: 频率
        :return: 不需返回
        """
        for x in range(self.x):
            for y in range(self.y):
                if random.randint(1,100) <= rate: #假设输入rate为50，那么随机生成的数小于50的概率为50%，每个点都有50%的几率被画上，这就是随机画点，恶心人就把rate值提高
                    draw.point((x,y),fill=self.random_color(50,200))

    def verify_code(self):
        """
        生成验证码图片
        :return: 图片及正确答案
        """
        #创建image对象 ， 创建画布
        image = Image.new('RGB',(self.x,self.y),(255,255,255)) #‘RGB’代表的是使用光学三原色，创建纯白色背景画布，x为宽，y为高

        #创建font对象 字体
        file = os.path.dirname(os.path.abspath(__file__)) #找到当前的绝对路径
        font = ImageFont.truetype(f'{file}/HYYakuHei-85W.ttf',self.size) #然后拼接路径，使用此字体类型

        #创建draw对象，画笔，绘制图形，线和点
        draw = ImageDraw.Draw(image) #在此画布上生成一个对应的笔

        #绘制干扰线与干扰点
        self.random_lines(draw)
        self.random_points(draw,20) #rate给20，则1-100中，以随机取数，数小于等于20的概率，对每个像素点进行判断打点

        #随机生成字符答案，验证码值
        code = self.random_str()

        #用画笔将font类型的字体对应的进行字符内容和颜色的绘制
        for i in range(self.length):
            draw.text((35*i+5,3),code[i],font=font,fill=self.random_color(30,120))

        #模糊滤镜
        image = image.filter(ImageFilter.BLUR) # BLUR模糊滤镜

        #返回图形及验证码值
        return  image, code

def jwt_token(token,user=None,request=None): #设置默认值为None，
    """
    自定义登陆成功后的响应函数，登陆后的数据处理
    执行这个函数，账号密码肯定正确，手动校验验证码即可
    :param token: 令牌
    :param user: 登陆的用户
    :param request: 请求对象
    :return: 登陆接口响应的内容和token
    """
    param = request.data #请求的数据来源(客户输入的数据)
    uuid = param.get('uuid') #获取uuid
    verify = param.get('verify') #获取用户穿进来的验证码

    if not uuid or not verify:
        return {'msg':'请输入验证码'}

    #得到redis缓存的该客户端的验证码答案与传入进来的验证码进行对比0判断
    cache = get_redis_connection(alias='verify_codes')
    redis_verify = cache.get(LOGIN_KEY_TEMPLATE % uuid) #从数据库里得到验证码(这个验证码是电脑自动生成的，不是客户填进来的数据)
    cache.delete(LOGIN_KEY_TEMPLATE % uuid) #得到数据之后就删除，防止别人用代码挨个试给试出来

    if not redis_verify:
        return {'msg':'验证码已过期'}

    if redis_verify.upper() != verify.upper():
        return {'msg':'验证码错误'}

    return {
        'token':token,
        'id':user.id,
        'username':user.username,
        'avatar': user.userdetail.avatar if hasattr(user,'userdetail') else None #有就返回用户详情中的头像，没有则返回空
    }



if __name__ == '__main__':  #测试代码
    imgVerify = ImageVerify() #验证码对象实例化一个验证码
    img,code = imgVerify.verify_code()
    # with open('test.png','wb')as fp:
    #     img.save(fp) #将图片保存到test.png里，而 fp.write()是把二进制内容携带文件里
    print(code)
